#include "Terreno.h"

int encontrarUltimoVertice(const float* alturas, int primerVertice, unsigned int ancho) {
	bool encontrado = false;
	unsigned int i = primerVertice + 1;
	while(!encontrado && (i < ancho)) {
		if (alturas[i] == 0) {
			encontrado = true;
		} else {
			i++;
		}
	}
	return i;
}

Terreno::Terreno(const float* alturas, float escalaX, unsigned int ancho, b2World &mundo) {
	this->ancho = ancho;
	this->escalaX = escalaX;
	toleranciaX = StageParser::getInstance()->getGameStageData().getLUWindowWidth() * STEP;
	toleranciaY = StageParser::getInstance()->getGameStageData().getLUWindowHigh() * STEP;
	b2BodyDef terrenoBodyDef;
	terrenoBodyDef.position.Set(ORIGEN_X, ORIGEN_Y);
	terrenoBody = mundo.CreateBody(&terrenoBodyDef);
	unsigned int primerVertice = 0;
	while(primerVertice < ancho) {
		if (alturas[primerVertice] > 0.0f) {
			int ultimoVertice = encontrarUltimoVertice(alturas, primerVertice, ancho);
			construirRelieve(alturas, primerVertice, ultimoVertice);
			primerVertice = ultimoVertice + 1;
		} else {
			primerVertice++;
		}
	}
	iniciarRelieves();
}

/*
void Terreno::construirRelieve(const float* alturas, int primerVertice, int ultimoVertice) {
	int count = (ultimoVertice - primerVertice) / STEP;
	b2Vec2* vertices = new b2Vec2[count];
	for(int i = 0; i < count - 1; i++) {
		vertices[i].Set((primerVertice + (i * STEP)) / escalaX, alturas[primerVertice+i*STEP]);
	}
	vertices[count-1].Set(ultimoVertice / escalaX, alturas[ultimoVertice]);
	
	
	b2ChainShape relieve;
	relieves.push_back(relieve);
	relieves.back().CreateChain(vertices, count);
	delete vertices;
}
*/

void Terreno::construirRelieve(const float* alturas, int primerVertice, int ultimoVertice) {
	int i;
	int j = 0;
	vector<b2Vec2> vertices;
	vertices.push_back(b2Vec2(primerVertice / escalaX, alturas[primerVertice-1]));
	for (i = primerVertice +1; i < ultimoVertice; i++) {
		if (abs(alturas[i] - vertices[j].y) >= toleranciaY ||
			abs(alturas[i] - alturas[i + 1]) >= toleranciaY ||
			(i / escalaX) - vertices[j].x >= toleranciaX) {
			j++;
			vertices.push_back(b2Vec2(i / escalaX, alturas[i - 1]));

			if (alturas[i+1] >= alturaMaxima) {
				alturaMaxima = alturas[i + 1];
			}
		}
	}
	vertices.push_back(b2Vec2(ultimoVertice / escalaX, alturas[ultimoVertice]));

	b2ChainShape relieve;
	relieves.push_back(relieve);
	relieves.back().CreateChain(&vertices[0], vertices.size());
}

void Terreno::iniciarRelieves() {
	for (list<b2ChainShape>::iterator it = relieves.begin(); it != relieves.end(); it++) {
		b2FixtureDef fixtureDef;
		fixtureDef.shape = &*it;
		fixtureDef.friction = StageParser::getInstance()->getGameStageData().getGroundCoef();
		fixtureDef.density = CHAIN_DENSITY;
		terrenoBody->CreateFixture(&fixtureDef);
	}
}

Terreno::~Terreno() {
}